package com.ctlele.team.space.fragment.impl;

import static android.app.Activity.RESULT_OK;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Handler;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;

import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.core.content.FileProvider;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.alibaba.fastjson.JSON;
import com.ctlele.team.space.R;
import com.ctlele.team.space.activity.BaseActivity;
import com.ctlele.team.space.activity.impl.*;
import com.ctlele.team.space.adapter.FileItemAdapter;
import com.ctlele.team.space.api.Api;
import com.ctlele.team.space.api.ApiStatusCode;
import com.ctlele.team.space.api.Apis;
import com.ctlele.team.space.entity.vo.FileItemVo;
import com.ctlele.team.space.entity.vo.FileTypeVo;
import com.ctlele.team.space.entity.vo.resp.FileListResp;
import com.ctlele.team.space.fragment.BaseFragment;
import com.ctlele.team.space.util.FileTypeUtils;
import com.ctlele.team.space.util.InputStreamUtils;
import com.ctlele.team.space.util.UriUtils;
import com.ctlele.team.space.widget.dialog.ImageDialog;
import com.ctlele.team.space.widget.dialog.InputDialog;
import com.ctlele.team.space.widget.dialog.MsgDialog;
import com.ctlele.team.space.widget.toast.IToast;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.scwang.smart.refresh.footer.BallPulseFooter;
import com.scwang.smart.refresh.header.MaterialHeader;
import com.scwang.smart.refresh.layout.SmartRefreshLayout;
import com.yanzhenjie.permission.AndPermission;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicInteger;

import okhttp3.Call;
import okhttp3.Response;

/**
 * 我的网盘页面
 *
 * @author stewiechen
 * @date 2023-04-20
 */
public class FileListFragment extends BaseFragment {

    private static final String TAG = "FileListFragment";

    /**
     * 文件列表模式 个人/团队
     */
    private final Mode mMode;

    /**
     * 团队ID
     */
    private String mGroupId = "";

    private static volatile boolean sRoute2Login = false;

    /*
     * 通过延时避免多个Fragment同时跳转到登录页面
     * 具体可以通过设置一个同步布尔值在第一个Fragment跳转的时候进行标记
     * 在后面的Fragment要跳转的时候检查该变量 如果为true则不跳转
     * 并在0.5秒后重置该变量
     */
    private static final Handler sDelayLoginRouteHandler = new Handler();

    /**
     * 当前目录
     */
    private final Stack<String> mCurrentDir = new Stack<>();

    /**
     * 当前数据页
     */
    private final AtomicInteger mPage = new AtomicInteger(1);

    /**
     * 数据页大小
     */
    private static final int PAGE_LIMIT = 10;

    /**
     * 返回上一级
     */
    private FloatingActionButton mReturnDir;

    /**
     * 打开文件管理器
     */
    private FloatingActionButton mOpenFileSelect;

    /**
     * 打开摄像头
     */
    private FloatingActionButton mOpenCamera;

    /**
     * 创建文件夹
     */
    private FloatingActionButton mCreateDir;

    private RecyclerView mRecyclerView;

    private SmartRefreshLayout mSmartRefreshLayout;

    private FileItemAdapter mAdapter;

    private Uri mImageUri;

    private static final Object lock = new Object();

    public enum Mode {
        user, group
    }

    public FileListFragment(Mode fileListEnum) {
        mMode = fileListEnum;
    }

    /**
     * 创建团队文件列表
     */
    public static FileListFragment createGroupFileList() {
        return new FileListFragment(Mode.group);
    }

    /**
     * 创建个人文件列表
     */
    public static FileListFragment createUserFileList() {
        return new FileListFragment(Mode.user);
    }

    ActivityResultLauncher<Intent> mOpenCameraLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
        if (result.getResultCode() == RESULT_OK) {
            if (mImageUri == null) {
                IToast.fail(getContext(), "拍照失败");
                return;
            }
            Uri copyUri;
            synchronized (lock) {
                copyUri = mImageUri;
                mImageUri = null;
            }
            new Thread(() -> {
                try (InputStream stream = getContext().getContentResolver().openInputStream(copyUri)) {
                    byte[] data = InputStreamUtils.readStream(stream);
                    getActivity().runOnUiThread(() -> {
                        ImageDialog dialog = new ImageDialog(getContext());
                        dialog.setOkText("上传");
                        dialog.setOnOk(view -> {
                            new Thread(() -> {
                                String filePath = UriUtils.getFilePathFromURI(getContext(), copyUri);
                                uploadFile(filePath, data);
                            }).start();
                            dialog.dismiss();
                        });
                        dialog.loadImage(data);
                        dialog.show();
                    });
                } catch (Exception e) {
                    Log.e(TAG, e.getMessage(), e);
                }
            }).start();
        }
    });

    /**
     * 文件管理器启动器
     */
    private final ActivityResultLauncher<String> mSelectFileLauncher = registerForActivityResult(new ActivityResultContracts.GetContent(), new ActivityResultCallback<Uri>() {
        @Override
        public void onActivityResult(Uri result) {
            if (result == null) {
                IToast.fail(getContext(), "未选择文件");
                return;
            }

            // 运行时授权访问文件存储
            AndPermission.with(getContext())
                    .permission(Manifest.permission.READ_EXTERNAL_STORAGE)
                    .rationale((context, permissions, executor) -> executor.execute())
                    .onGranted(permissions -> {
                        String fileAbsolutePath = UriUtils.getFileAbsolutePath(getContext(), result);
                        Log.i(TAG, fileAbsolutePath);
                        try (InputStream fileInputStream = getActivity().getContentResolver().openInputStream(result)) {
                            uploadFile(fileAbsolutePath, fileInputStream);
                        } catch (Exception e) {
                            Log.e(TAG, e.getMessage(), e);
                        }
                    })
                    .onDenied(permissions -> {
                        IToast.fail(getContext(), "授权失败");
                    })
                    .start();
        }
    });

    {
        // 根目录
        mCurrentDir.push("0");
    }

    private enum DataOperation {
        load, refresh
    }

    @Override
    protected int initLayout() {
        return R.layout.fragment_file_list;
    }

    @Override
    protected void initView() {
        mOpenFileSelect = mRootView.findViewById(R.id.open_file_select);
        mOpenCamera = mRootView.findViewById(R.id.open_photo);
        mCreateDir = mRootView.findViewById(R.id.create_dir);
        mReturnDir = mRootView.findViewById(R.id.return_dir);
        mRecyclerView = mRootView.findViewById(R.id.file_list);
        mSmartRefreshLayout = mRootView.findViewById(R.id.refresh_layout);
        mAdapter = new FileItemAdapter((BaseActivity) getActivity());
    }

    @Override
    protected void initData() {
        // 文件夹被点击时
        mAdapter.setOnDirClick((item) -> {
            // 团队模式
            if (mMode == Mode.group && !TextUtils.isEmpty(item.getDocGroupId())) {
                mGroupId = item.getDocGroupId();
            }
            mCurrentDir.push(item.getDocId());
            getFileList(DataOperation.refresh);
        });

        // 文件被点击时
        mAdapter.setOnFileClick(item -> {
            FileTypeVo type = FileTypeUtils.fromId(item.getDocType());
            switch (type.getTypeSimpleName()) {
                case "video":
                    Intent videoView = new Intent(getContext(), IjkPLayerActivity.class);
                    videoView.putExtra(IjkPLayerActivity.URL_KEY, item.getOriginPath()); // 设置视频播放URL
                    videoView.putExtra(IjkPLayerActivity.VIDEO_TITLE_KEY, item.getDocName()); // 设置视频标题
                    videoView.putExtra(IjkPLayerActivity.CONVERT_KEY, item.getThumbPath()); // 设置预览图
                    startActivity(videoView);
                    return;
                case "pptx":
                    Intent pptView = new Intent(getContext(), PdfViewActivity.class);
                    pptView.putExtra(PdfViewActivity.TITLE_KEY, "在线预览");
                    pptView.putExtra(PdfViewActivity.URL_KEY, item.getHtmlPath());
                    startActivity(pptView);
                    return;
                case "pdf":
                    Intent pdfView = new Intent(getContext(), PdfViewActivity.class);
                    pdfView.putExtra(PdfViewActivity.TITLE_KEY, "在线预览");
                    pdfView.putExtra(PdfViewActivity.URL_KEY, item.getOriginPath());
                    startActivity(pdfView);
                    return;
                case "md":
                case "mde":
                    Intent mdView = new Intent(getContext(), MarkdownPreviewActivity.class);
                    mdView.putExtra(MarkdownPreviewActivity.URL_KEY, item.getOriginPath());
                    mdView.putExtra(MarkdownPreviewActivity.TITLE_KEY, "在线预览");
                    startActivity(mdView);
                    return;
                default:
                    if (!TextUtils.isEmpty(item.getHtmlPath()) &&
                            item.getHtmlPath().startsWith("http")) {
                        Intent intent = new Intent(getContext(), WebViewActivity.class);
                        intent.putExtra(WebViewActivity.TITLE_KEY, "在线预览");
                        intent.putExtra(WebViewActivity.URL_KEY, item.getHtmlPath());
                        startActivity(intent);
                    } else {
                        IToast.fail(getContext(), "该文件暂不支持预览");
                    }
                    return;
            }
        });
        mAdapter.setAfterDelete(() -> getFileList(DataOperation.refresh));
        mRecyclerView.setAdapter(mAdapter);

        LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getContext());
        linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        mRecyclerView.setLayoutManager(linearLayoutManager);

        mSmartRefreshLayout.setRefreshHeader(new MaterialHeader(getActivity()));
        mSmartRefreshLayout.setRefreshFooter(new BallPulseFooter(getActivity()));
        mSmartRefreshLayout.setOnRefreshListener((refresher) -> {
            mPage.set(1);
            getFileList(DataOperation.refresh);
        });
        mSmartRefreshLayout.setOnLoadMoreListener((refresher) -> {
            mPage.incrementAndGet();
            getFileList(DataOperation.load);
        });

        mReturnDir.setOnClickListener(view -> {
            if ("0".equals(mCurrentDir.peek())) {
                IToast.alert(getContext(), "当前处于根目录");
            } else {
                if (!"0".equals(mCurrentDir.peek())) {
                    mCurrentDir.pop();
                    // 团队模式
                    if (mMode == Mode.group && "0".equals(mCurrentDir.peek())) {
                        mGroupId = "";
                    }
                }
                getFileList(DataOperation.refresh);
            }
        });

        mOpenFileSelect.setOnClickListener(view -> {
            mSelectFileLauncher.launch("*/*");
        });

        mOpenCamera.setOnClickListener(view -> {
            long curr = System.nanoTime();
            File file = new File(getActivity().getExternalCacheDir(), curr + ".jpg");
            Uri uri;
            if (Build.VERSION.SDK_INT >= 24) {
                uri = FileProvider.getUriForFile(getContext(), "com.ctlele.team.space.fileprovider", file);
            } else {
                uri = Uri.fromFile(file);
            }
            Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
            intent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
            mImageUri = uri;
            mOpenCameraLauncher.launch(intent);
        });

        mCreateDir.setOnClickListener(view -> {
            InputDialog dialog = new InputDialog(getContext());
            dialog.setTitle("请输入文件夹名");
            dialog.setOnOk(v -> {
                String dirName = dialog.getText();
                List<Api.RequestParam> params = new ArrayList<>();
                params.add(new Api.RequestParam("parentId", mCurrentDir.peek()));
                params.add(new Api.RequestParam("docName", dirName));
                // 团队模式
                if (mMode == Mode.group) {
                    if ("0".equals(mCurrentDir.peek())) {
                        IToast.fail(getContext(), "请先创建团队");
                        return;
                    }
                    params.add(new Api.RequestParam("docGroupId", mGroupId));
                }
                Api.postForm(getContext(), Apis.CREATE_DIR, params, new Api.ApiCallback() {
                    @Override
                    public void onFailure(Context context, Call call, IOException e) {
                        Log.e(TAG, e.getMessage(), e);
                    }

                    @Override
                    public void onResponse(Context context, Call call, Response response) throws IOException {
                        getFileList(DataOperation.refresh);
                    }
                });
                dialog.dismiss();
            });
            dialog.show();
        });

        // 页面加载时初始化数据
        getFileList(DataOperation.refresh);
    }

    private void getFileList(DataOperation operation) {
        if (operation == DataOperation.refresh) {
            mPage.set(1);
        }
        List<Api.RequestParam> params = new ArrayList<>();
        params.add(new Api.RequestParam("page", String.valueOf(mPage)));
        params.add(new Api.RequestParam("limit", String.valueOf(PAGE_LIMIT)));
        params.add(new Api.RequestParam("parentId", mCurrentDir.peek()));
        // 团队模式
        String api;
        switch (mMode) {
            case user:
                api = Apis.USER_FILE_LIST;
                break;
            case group:
                api = Apis.GROUP_FILE_LIST;
                params.add(new Api.RequestParam("docGroupId", mGroupId));
                break;
            default:
                api = Apis.USER_FILE_LIST;
                break;
        }
        Api.get(getContext(), api, params, new Api.ApiCallback() {
            @Override
            public void onFailure(Context context, Call call, IOException e) {
                Log.e(TAG, e.getMessage(), e);
            }

            @Override
            public void onResponse(Context context, Call call, Response response) throws IOException {
                String res = response.body().string();
                FileListResp resp = JSON.parseObject(res, FileListResp.class);
                if (resp != null && resp.getCode().equals(ApiStatusCode.OK)) {
                    List<FileItemVo> list = resp.getData();
                    flushData(operation, list);
                } else {
                    reload();
                    if (!sRoute2Login) {
                        sRoute2Login = true;
                        sDelayLoginRouteHandler.postDelayed(() -> sRoute2Login = false, 500);
                        getActivity().runOnUiThread(() -> {
                            IToast.fail(context, "用户未登录").andOnUiThread(() -> turnTo(LoginActivity.class));
                        });
                    }
                }
                closeLoading(operation);
            }
        });
    }

    private void flushData(DataOperation operation, List<FileItemVo> list) {
        Log.i(TAG, operation.name());
        switch (operation) {
            case load:
                if (list == null || list.isEmpty()) {
                    mPage.decrementAndGet();
                }
                mAdapter.appendData(list);
                break;
            case refresh:
                mAdapter.flushData(list);
                getActivity().runOnUiThread(() -> mRecyclerView.scrollToPosition(0));
                break;
        }
    }

    private void closeLoading(DataOperation operation) {
        switch (operation) {
            case refresh:
                mSmartRefreshLayout.finishRefresh(true);
                break;
            case load:
                mSmartRefreshLayout.finishLoadMore(true);
                break;
        }
    }

    private void uploadFile(String filePath, InputStream fileInputStream) throws IOException {
        uploadFile(filePath, InputStreamUtils.readStream(fileInputStream));
    }

    private void uploadFile(String filePath, byte[] data) {
        File file = new File(filePath);

        // 根据文件名获取文件类型
        FileTypeVo fileType = FileTypeUtils.fromContentType(getContext(), file.getName());

        List<Api.RequestParam> params = new ArrayList<>();
        params.add(new Api.RequestParam("parentId", mCurrentDir.peek()));
        params.add(new Api.RequestParam("chunks", "1"));
        params.add(new Api.RequestParam("chunk", "0"));
        params.add(new Api.RequestParam("type", fileType.getTypeId()));
        // 团队模式
        if (mMode == Mode.group) {
            if ("0".equals(mCurrentDir.peek())) {
                getActivity().runOnUiThread(() -> {
                    IToast.fail(getContext(), "请先创建团队");
                });
                return;
            }
            params.add(new Api.RequestParam("docGroupId", mGroupId));
        }
        Api.postFile(getContext(), Apis.UPLOAD_IMAGE, "file", file.getName(), data, params, new Api.ApiCallback() {
            @Override
            public void onFailure(Context context, Call call, IOException e) {
                Log.e(TAG, e.getMessage(), e);
                IToast.fail(getContext(), "上传失败");
            }

            @Override
            public void onResponse(Context context, Call call, Response response) throws IOException {
                IToast.success(getContext(), "上传成功").andOnUiThread(() -> getFileList(DataOperation.refresh));
            }
        });
    }
}